package com.mx.swipe

import android.content.Context
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import android.view.ViewConfiguration
import android.widget.LinearLayout
import android.widget.Scroller
import com.mx.swipe_layout.R
import kotlin.math.abs

class MXSwipeLayout @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : LinearLayout(context, attrs, defStyleAttr) {
    /**
     * 内容部分
     */
    private var contentView: View? = null

    /**
     * 内容宽度
     */
    private var contentWidth = 0

    /**
     * 滑层的按钮
     */
    private var swipeView: View? = null

    /**
     * 滑层的宽度
     */
    private var swipeWidth = 0

    /**
     * 滑动计算器
     */
    private val scroller = Scroller(context)


    private var xDown = 0f
    private var xOldDown = 0f
    private var yDown = 0f
    private var xMove = 0f
    private var yMove = 0f
    private var xDistance = 0f
    private var xAbsDistance = 0f
    private var yDistance = 0f

    private var swipeVisible = false

    init {
        val typedArray = context.obtainStyledAttributes(attrs, R.styleable.MXSwipeLayout)
        //根据属性名称获取对应的值，属性名称的格式为类名_属性名
        try {
            swipeVisible = typedArray.getBoolean(R.styleable.MXSwipeLayout_show_swipe, false)
        } catch (e: Exception) {
        }
        typedArray.recycle()
        orientation = HORIZONTAL
    }

    override fun onFinishInflate() {
        super.onFinishInflate()
        check(childCount == 2) { MXSwipeLayout::class.java.simpleName + "必须有且只有两个子控件" }
        contentView = getChildAt(0)
        swipeView = getChildAt(1)
    }


    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        contentView?.measure(widthMeasureSpec, heightMeasureSpec)
//        swipeView?.measure(MeasureSpec.UNSPECIFIED, heightMeasureSpec)
    }

    override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
        super.onLayout(changed, l, t, r, b)
        if (contentWidth <= 0) {
            contentWidth = contentView?.width ?: 0
            swipeWidth = swipeView?.width ?: 0
            //  @see reset()
            if (swipeVisible) {
                scrollBy(swipeWidth, 0)
            }
        }
    }

    /**
     * 临界值设为 50px , 保证不会稍微动一点点就会拦截事件
     */
    private val criticalValue = ViewConfiguration.get(context).scaledTouchSlop

    override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
        log("onInterceptTouchEvent()  ${ev.action}")
        when (ev.action) {
            MotionEvent.ACTION_DOWN -> {
                if (!scroller.isFinished) {
                    scroller.forceFinished(true)
                }
                curState = TOUCH_DOWN
                xDown = ev.x
                xOldDown = xDown
                yDown = ev.y
            }
            MotionEvent.ACTION_MOVE -> {
                xMove = ev.x
                yMove = ev.y
                xDistance = xMove - xDown
                yDistance = yMove - yDown
                // 先判断用户是左右滑动还是上下滑动，因为用户可能是先右滑，再左滑，所以使用绝对值，但是右滑不需要进行滚动，所以在 onTouch方法中进行判断
                if (abs(xDistance) > criticalValue && abs(xDistance) > abs(yDistance)) {
                    // 请求父类对后续移动事件不进行拦截，这个 flag 会在每一次 down 时被父类自动重置
                    parent.requestDisallowInterceptTouchEvent(true)
                    return true
                }
            }
            else -> {
            }
        }
        return super.onInterceptTouchEvent(ev)
    }


    private val TOUCH_DOWN: Byte = 0
    private val TOUCH_MOVE: Byte = 1
    private val TOUCH_UP: Byte = 2
    private var curState = TOUCH_DOWN

    override fun onTouchEvent(event: MotionEvent): Boolean {
        log("onTouchEvent()  ${event.action}")
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                return true
            }
            MotionEvent.ACTION_MOVE -> {
                xMove = event.x
                yMove = event.y
                xDistance = xMove - xDown
                yDistance = yMove - yDown
                xDown = xMove
                xAbsDistance = xMove - xOldDown
                if (curState == TOUCH_DOWN) {
                    if (abs(xDistance) > abs(yDistance)) {
                        curState = TOUCH_MOVE
                    }
                }

                // 当移动时，判断viewBottom状态，如果显示，则只能右拉，如果不显示则只能左拉
                if (curState == TOUCH_MOVE) {
                    if (swipeVisible) {
                        if (xAbsDistance >= 0 && abs(xAbsDistance) <= swipeWidth) {
                            scrollBy((-xDistance).toInt(), 0)
                        }
                    } else {
                        if (xAbsDistance <= 0 && abs(xAbsDistance) <= swipeWidth) {
                            scrollBy((-xDistance).toInt(), 0)
                        }
                    }
                }
                return true
            }
            MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> if (curState == TOUCH_MOVE) {
                curState = TOUCH_UP
                val moveWidth: Int
                if (scrollX >= swipeWidth / 2) {
                    swipeVisible = true
                    moveWidth = swipeWidth - scrollX
                } else {
                    swipeVisible = false
                    moveWidth = -scrollX
                }
                swipeViewChangedListener?.invoke(swipeVisible)

                if (moveWidth != 0) {
                    scroller.startScroll(scrollX, 0, moveWidth, 0, 300)
                    postInvalidate()
                }
                return true
            }
            else -> {
            }
        }
        return super.onTouchEvent(event)
    }

    override fun computeScroll() {
        super.computeScroll()
        if (scroller.computeScrollOffset() && curState == TOUCH_UP) {
            var v = scroller.currX
            //执行 scrollTo
            if (v < 0) {
                v = 0
            }
            scrollTo(v, 0)
            postInvalidate()
        }
    }


    private var swipeViewChangedListener: ((Boolean) -> Unit)? = null
    fun setOnSwipeChangedListener(onBottomViewChangedListener: ((Boolean) -> Unit)?) {
        this.swipeViewChangedListener = onBottomViewChangedListener
    }

    /**
     * 重置考虑两种情况
     * 1、控件已存在，那这时候 viewBottomWidth != 0,直接 reset就可以
     * 2、控件不存在，那这时候的控件只是在View树存在对象，即只是完成了 onFinishInflate() 函数，但是还未走测量等方法，这时候就需要在
     * onLayout内对控件进行布局设置。
     */
    fun reset(viewBottomVisible: Boolean) {
        log("reset()")
        this.swipeVisible = viewBottomVisible
        if (swipeWidth == 0) {
            return
        }
        if (viewBottomVisible) {
            scrollBy(if (scrollX == 0) swipeWidth else 0, 0)
        } else {
            scrollBy(if (scrollX != 0) -scrollX else 0, 0)
        }
    }

    private fun log(log: String) {
        android.util.Log.i("SwipeLayout", log)
    }
}